import { Utils } from "../tool/utils";
import { CreateHandleTo, IHandle, RemoveHandle } from "./data-handle";


/**
 * 抽象数据类
 */
abstract class AbstractData {

    /**
     * 强制触发更新行为（如初始化等特殊状态时，需要强制执行更新行为）
     */
    public force: boolean = false;

    public noChangeHandle: boolean = false;

    /**
     * 父级数据
     */
    public parent: GroupData | null = null;

    /**
     * 更新值或子级数据
     */
    public abstract change(): void;

    /**
     * 重置数据到初始值
     * @param force 强制出发更新行为
     */
    public abstract reset(force: boolean): void;

    /**
     * 销毁
     * @param recursive 是否遍历销毁成员数据
     */
    public abstract dispose(recursive: boolean): void;
}


/**
 * 值类型数据
 */
abstract class ValueData<T> extends AbstractData {

    private _originalValue: T[] = [];
    private _previousValue: T[] = [];

    protected currentValue: T[] = [];
    protected changeHandles: Array<IHandle<T>> = [];

    public originalValueWillUpdate: boolean = false;

    constructor(value: T) {
        super();
        this._originalValue = [this.generate(value)];
        this._previousValue = [this.generate(value)];
        this.currentValue = [this.generate(value)];
    }

    /**
     * 当前值
     */
    public get value(): T {
        return this.currentValue[0];
    }

    public set value(value: T) {
        if (this.originalValueWillUpdate) {
            this.copy(this._originalValue, value);
            this.originalValueWillUpdate = false;
        }
        if (this.equal(this.currentValue[0], value) && (!this.force)) return;
        this.copy(this._previousValue, this.currentValue[0]);
        this.copy(this.currentValue, value);
        this.change();
        if (this.parent) this.parent.change();
    }

    /**
     * 初始值
     */
    public get original(): T {
        return this._originalValue[0];
    }

    /**
     * 上一个值
     */
    public get previous(): T {
        return this._previousValue[0];
    }

    /**
     * 添加更新回调函数
     * @param func 更新回调函数(oldValue:旧值,newValue:新值):void
     * @returns 自动生成的回调函数id
     */
    public onChange(func: { (oldValue: T, newValue: T): void }): IHandle<T> {
        return CreateHandleTo<T>(func, this.changeHandles);
    }

    public change(): void {
        this.changeHandles.forEach(handle => {
            if (!this.noChangeHandle) handle.callback(this._previousValue[0], this.currentValue[0]);
        });
    }

    public removeChangeHandle(handle: number | IHandle<T>): void {
        RemoveHandle(handle, this.changeHandles);
    }

    public reset(force: boolean): void {
        let oriForce = this.force;
        this.force = force;
        this.value = this._originalValue[0];
        this.force = oriForce;
    }

    /**
     * 创建值的方法
     * @param from 输入值
     */
    protected abstract generate(from: T): T;

    /**
     * 判断值相等的方法
     * @param a 值a
     * @param b 值b
     */
    protected abstract equal(a: T, b: T): boolean;

    /**
     * 值的拷贝方法
     * @param target 目标
     * @param source 源
     */
    protected abstract copy(targetContainer: T[], source: T): void;

    public dispose(recursive: boolean = false): void {
        this.changeHandles.length = 0;
    }
}


/**
 * 值集合类型数据
 */
abstract class ValueArrayData<T> extends ValueData<T[]> {

    private _val: T[] = [];
    private _tmpVal: Array<T | T[]> = [];

    public orderedEqual: boolean = true;

    /**
     * 添加值
     * @param index 插入位置 
     * @param noDulpication 滤除重复值
     * @param values 要添加的值
     */
    public addValues(index: number, noDulpication: boolean, ...values: T[]): void {
        const tmv = this._tmpVal;
        const val = this._val;
        tmv.length = 0;
        tmv.push(...(this.value as T[]));
        val.length = 0;
        val.push(...values);
        if (noDulpication) {
            Utils.noDuplication(val, this.itemEqual.bind(this));
            for (let i = 0; i < val.length; i++) {
                if (this.hasValue(val[i], (tmv as T[]))) {
                    val.splice(i, 1);
                    i--;
                }
            }
        }
        if (index < 0) {
            tmv.unshift(val);
        } else if (index > tmv.length - 1) {
            tmv.push(val);
        } else {
            for (let i = 0; i < tmv.length; i++) {
                if (i === index) {
                    tmv.splice(index, 0, val);
                }
            }
        }
        (this.value as T[]) = tmv.flat() as T[];
    }

    /**
     * 向左侧添加值（不滤除重复值）
     * @param values 
     */
    public addToLeft(...values: T[]): void {
        this.addValues(-1, false, ...values);
    }

    /**
     * 向左侧添加不重复的值
     * @param values 
     */
    public addToLeftNoDulpication(...values: T[]): void {
        this.addValues(-1, true, ...values);
    }

    /**
     * 向右侧添加值（不滤除重复值）
     * @param values 
     */
    public addToRight(...values: T[]): void {
        this.addValues(Number.POSITIVE_INFINITY, false, ...values);
    }

    /**
     * 向右侧添加不重复的值
     * @param values 
     */
    public addToRightNoDuplication(...values: T[]): void {
        this.addValues(Number.POSITIVE_INFINITY, true, ...values);
    }

    /**
     * 移除给定索引的值
     * @param indices 
     */
    public removeByIndices(...indices: number[]): void {
        Utils.quickSort(indices, undefined);
        const val = this._val;
        val.length = 0;
        val.push(...(this.value as T[]));
        for (let i = indices.length - 1; i >= 0; i--) {
            val.splice(i, 1);
        }
        (this.value as T[]) = val;
    }

    /**
     * 移除给定值（所有位置）
     * @param values 
     */
    public removeValue(...values: T[]): void {
        this.removeByValue(0, false, values);
    }

    /**
     * 从左侧移除一个给定值
     * @param values 
     */
    public removeValueFromLeft(...values: T[]): void {
        this.removeByValue(0, true, values);
    }

    /**
     * 从右侧移除一个给定值
     * @param values 
     */
    public removeValueFromRight(...values: T[]): void {
        this.removeByValue(1, true, values);
    }

    /**
     * 滤除集合中的重复值
     */
    public noDuplication(): void {
        const val = this._val;
        val.length = 0;
        val.push(...(this.value as T[]));
        for (const v of val) {
            let count = 0;
            for (let i = 0; i < val.length; i++) {
                if (this.itemEqual(v, val[i])) count++;
                if (count > 1) {
                    val.splice(i, 1);
                    break;
                }
            }
        }
        (this.value as T[]) = val;
    }

    /**
     * 清除所有值
     */
    public clear(): void {
        const val = this._val;
        val.length = 0;
        (this.value as T[]) = val;
    }

    /**
     * 查询给定值的索引（所有位置，升序）
     * @param value 要查询的值
     * @param out 索引集合结果
     * @returns 索引集合结果
     */
    public indexOf(value: T, out: number[]): number[] {
        const res: number[] = out || [];
        const vals = this.value as T[];
        for (let i = 0; i < vals.length; i++) {
            if (this.itemEqual(value, vals[i])) res.push(i);
        }
        return res;
    }

    /**
     * 值是否已经存在
     * @param val 目标值
     * @param vals 值集合
     * @returns 是否存在
     */
    private hasValue(val: T, vals: T[]): boolean {
        for (const v of vals) {
            if (this.itemEqual(v, val)) return true;
        }
        return false;
    }

    /**
     * 根据值进行移除
     * @param direction 遍历方向（0：升序，1：降序）
     * @param once 是否只移除一个
     * @param values 值集合
     */
    private removeByValue(direction: 0 | 1, once: boolean, values: T[]): void {
        const val = this._val;
        val.length = 0;
        val.push(...(this.value as T[]));
        for (const value of values) {
            switch (direction) {
                case 0:
                    for (let i = 0; i < val.length; i++) {
                        if (this.itemEqual(value, val[i])) {
                            val.splice(i, 1);
                            if (once) break;
                        }
                    }
                    break;
                case 1:
                    for (let i = val.length - 1; i >= 0; i--) {
                        if (this.itemEqual(value, val[i])) {
                            val.splice(i, 1);
                            if (once) break;
                        }
                    }
                    break;
            }
        }
        (this.value as T[]) = val;
    }

    /**
     * 集合成员相等函数
     * @param a 值1
     * @param b 值2
     * @returns 是否相等
     */
    protected abstract itemEqual(a: T, b: T): boolean;

    /**
     * 集合相等函数
     * @param a 集合1
     * @param b 集合2
     * @returns 是否相等
     */
    protected equal(a: T[], b: T[]): boolean {
        if (a.length !== b.length) return false;
        for (let i = 0; i < a.length; i++) {
            if (this.orderedEqual) {
                if (a[i] !== b[i]) return false;
            } else {
                const idx = b.findIndex(vb => this.itemEqual(a[i], vb));
                if (idx < 0) return false;
            }
        }
        return true;
    }

}

/**
 * 组和类型数据（有若干值类型组成）
 */
class GroupData extends AbstractData {

    private _children: Array<AbstractData> = [];
    private _changeHandles: Array<IHandle<void>> = [];

    constructor(...datas: Array<AbstractData>) {
        super();
        this.add(...datas);
    }

    /**
     * 添加子级数据
     * @param datas 子数据(值数据或组数据)
     */
    public add(...datas: Array<AbstractData>): void {
        for (let data of datas) {
            if (data.parent !== null) {
                console.warn('cannot add the data to a group for twice!', data);
                continue;
            }
            data.parent = this;
            this._children.push(data);
        }
    }

    /**
     * 添加值改变时的回调函数
     * @param func 回调函数
     * @returns 回调函数对象
     */
    public onChange(func: { (): void }): IHandle<void> {
        return CreateHandleTo<void>(func, this._changeHandles);
    }

    /**
     * 执行所有值改变回调函数
     */
    public change(): void {
        this._changeHandles.forEach(handle => {
            if (!this.noChangeHandle) handle.callback();
        });
    }

    /**
     * 移除值改变回调函数对象
     * @param handle 回调函数对象或其id
     */
    public removeChangeHandle(handle: number | IHandle<void>): void {
        RemoveHandle(handle, this._changeHandles);
    }

    /**
     * 重置所有成员值
     * @param force 是否强制执行回调函数
     */
    public reset(force: boolean = false): void {
        this._children.forEach(data => {
            data.reset(force);
        });
    }

    public dispose(recursive: boolean = false): void {
        this._changeHandles.length = 0;
        if (!recursive) return;
        this._children.forEach(c => c.dispose(true));
    }

}


export { AbstractData, ValueData, ValueArrayData, GroupData };